package logger

import (
	"errors"
	"io"
	"os"
	"time"

	"gitee.com/by-fate/program"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// New 创建日志实例,可以传递context
func New(level LogLevel, opts ...Options) (Logger, error) {
	if level < DebugLevel || level > PanicLevel {
		return nil, errors.New("log level error")
	}
	var l = new(logger)
	l.Config = zapcore.EncoderConfig{
		TimeKey:        "datetime",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		FunctionKey:    zapcore.OmitKey,
		MessageKey:     "message",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
		EncodeLevel:    zapcore.CapitalLevelEncoder,
	}
	l.Option = []zap.Option{zap.AddCaller(), zap.AddCallerSkip(1)}
	l.Config.EncodeTime = zapcore.TimeEncoderOfLayout(time.DateTime)
	l.Encoder = zapcore.NewConsoleEncoder(l.Config)
	l.Level = level
	l.Channel = make(chan struct{}, 1)
	l.Interval = "\t"
	for _, v := range opts {
		v(l)
	}
	l.Split = time.Now().Day()
	switch l.Target {
	case outputFile:
		err := l.file()
		return l, err
	case outputBash:
		l.Output = l.output(os.Stdout)
		return l, nil
	default:
		return nil, errors.New("unknown log output target... ")
	}
}

func (l *logger) open(name string, lv LogLevel) (io.Writer, error) {
	filename := l.Dir + "/" + name + "_" +
		time.Now().Format(time.DateOnly) +
		"_" + logLevelString[lv] + ".log"
	return os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
}
func (l *logger) file() error {
	name, err := program.GetProgramName()
	if err != nil {
		return err
	}
	err = os.MkdirAll(l.Dir, os.ModePerm)
	if err != nil {
		return err
	}
	var file io.Writer
	if !l.FileLvSplit {
		file, err = l.open(name, l.Level)
		if err != nil {
			return err
		}
		l.Output = l.output(file)
		return nil
	}
	//panic
	file, err = l.open(name, PanicLevel)
	if err != nil {
		return err
	}
	l.File.panic = l.output(file)
	//error
	if l.Level > ErrorLevel {
		return nil
	}
	file, err = l.open(name, ErrorLevel)
	if err != nil {
		return err
	}
	l.File.error = l.output(file)
	//warn
	if l.Level > WarnLevel {
		return nil
	}
	file, err = l.open(name, WarnLevel)
	if err != nil {
		return err
	}
	l.File.warn = l.output(file)
	//info
	if l.Level > InfoLevel {
		return nil
	}
	file, err = l.open(name, InfoLevel)
	if err != nil {
		return err
	}
	l.File.info = l.output(file)
	//debug
	if l.Level > DebugLevel {
		return nil
	}
	file, err = l.open(name, DebugLevel)
	if err != nil {
		return err
	}
	l.File.debug = l.output(file)
	return nil
}
func (l *logger) output(target io.Writer) *zap.SugaredLogger {
	return zap.New(
		zapcore.NewCore(
			l.Encoder,
			zapcore.NewMultiWriteSyncer(zapcore.AddSync(target)),
			zapcore.Level(l.Level)),
		l.Option...,
	).Sugar()
}
